package _设计模式;

import _10_effective_java._2_CreateObject;
import java.lang.reflect.InvocationTargetException;

/**
 * 参考 effective java {@link _2_CreateObject#singletonWithEnum()}
 *
 */
public class SingletonByHand {

  private volatile static SingletonByHand singletonByHand;

  /** 双重检查, 不建议使用, jvm 可能会优化锁, 偶尔出问题 */
  public static SingletonByHand getInstance() throws IllegalAccessException {
    if (singletonByHand == null) {
      synchronized (SingletonByHand.class) {
        if (singletonByHand == null) {
          singletonByHand = new SingletonByHand();
        }
      }
    }
    return singletonByHand;
  }

  /** 私有构造器，让调用者无法调用，根据调用栈，解决反射调用对单例的破坏 */
  private SingletonByHand() throws IllegalAccessException {
    StackTraceElement[] stack = Thread.currentThread().getStackTrace();
    for (StackTraceElement element : stack) {
      String stackMethod = element.getClassName()+"."+ element.getMethodName();
      // System.out.println(stackMethod);
      if (stackMethod.contains("NativeConstructorAccessorImpl.newInstance0") ||
          stackMethod.contains("NativeConstructorAccessorImpl.newInstance")||
          stackMethod.contains("DelegatingConstructorAccessorImpl.newInstance")||
          stackMethod.contains("java.lang.reflect.Constructor.newInstance")
      ) {
        throw new IllegalArgumentException("Cannot reflectively create Singleton objects");
      }
    }
  }

  public static void main(String... args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
    System.out.println(getInstance());
    Object instance = SingletonByHand.class.getDeclaredConstructors()[0].newInstance();
    System.out.println(instance);
  }
}
